﻿global using System.Text;
using Microsoft.Extensions.Caching.Memory;
using OneCard.Face8280Module.Utility;
using OneCard.Face8280Module.DeviceModel.DTO.People;
using OneCard.Face8280Module.DeviceModel.DTO.People.Request;
using OneCard.Face8280Module.DeviceModel.DTO.WorkParameter;
using OneCard.Face8280Module.DeviceModel.Model;
using OneCard.Face8280Module.DeviceModel.Model.Access;
using OneCard.Face8280Module.Entities.DbModels;
using OneCard.Face8280Module.Entities.DTO.Access;
using OneCard.Face8280Module.Entities.DTO.Cache;
using SqlSugar;
using System.Web;
using OneCard.Face8280Module.Protocol.Model;

namespace OneCard.Face8280Module.Service
{
    public class DataService
    {
        private ISqlSugarClient DBClient;
        private CacheService Cache;
        private static object lockObject = new object();
        private const int FC8280EquptType = 11;

        private static Dictionary<int, byte> RecordCodeConvertTable;
        static DataService()
        {
            IniRecordCodeConvertTable();
        }

        /// <summary>
        /// 初始化记录类型映射表
        /// </summary>
        private static void IniRecordCodeConvertTable()
        {
            RecordCodeConvertTable = new Dictionary<int, byte>();
            RecordCodeConvertTable.Add(1, 0);//正常通行(已注册或者陌生人免验证)  | (开门事件)
            RecordCodeConvertTable.Add(2, 2);//未注册（陌生人）                        | (不开门事件)
            RecordCodeConvertTable.Add(3, 7);//有效期已过期或未到起始时间              | (不开门事件)
            RecordCodeConvertTable.Add(4, 39);//通行次数已用尽                          | (不开门事件
            RecordCodeConvertTable.Add(5, 8);//不在开门时段范围                        | (不开门事件) 
            RecordCodeConvertTable.Add(6, 25);//重复验证                                | (不开门事件) 
            RecordCodeConvertTable.Add(7, 181);//体温异常                                | (不开门事件)
            RecordCodeConvertTable.Add(8, 3);//使用出门按钮开门 （需要给信号确认IO口） | (开门事件) 
            RecordCodeConvertTable.Add(9, 93);//免验证开门                              | (开门事件)
            RecordCodeConvertTable.Add(10, 34);//黑名单验证                              | (不开门事件)
            RecordCodeConvertTable.Add(100, 80);//开门超时报警 （需要给信号确认IO口）     | (系统事件)
            RecordCodeConvertTable.Add(101, 14);//门磁报警（需要给信号确认IO口）          | (系统事件)
            RecordCodeConvertTable.Add(102, 10);//恢复出厂设置（清空所有人和记录）        | (系统事件)
            RecordCodeConvertTable.Add(103, 124);// 删除所有人                              | (系统事件)   ---124
            RecordCodeConvertTable.Add(104, 35);// 开机                                    | (系统事件)
            RecordCodeConvertTable.Add(106, 178);//WIFI 已连接                             | (系统事件 - 启用WIFI时才记录)  ---178
            RecordCodeConvertTable.Add(107, 179);//WIFI 连接已断开                         | (系统事件 - 启用WIFI时才记录)  ---179
            RecordCodeConvertTable.Add(108, 6);// 消防报警（需要给信号确认IO口）          | (系统事件)
            RecordCodeConvertTable.Add(109, 84);// 关闭开门超时报警                        | (系统事件)
            RecordCodeConvertTable.Add(110, 51);// 关闭门磁报警                            | (系统事件) 
            RecordCodeConvertTable.Add(111, 53);// 关闭消防报警                            | (系统事件) 
            RecordCodeConvertTable.Add(112, 79);// 黑名单报警                              | (系统事件) 
            RecordCodeConvertTable.Add(113, 83);// 关闭黑名单报警                          | (系统事件) 
            RecordCodeConvertTable.Add(114, 28);// 门磁开                                  | (系统事件)
            RecordCodeConvertTable.Add(115, 29);// 门磁关                                  | (系统事件)
            RecordCodeConvertTable.Add(116, 130);// 删除所有记录                           | (系统事件)
        }


        public DataService(ISqlSugarClient db, CacheService cache)
        {
            DBClient = db;
            Cache = cache;
        }

        #region 缓存

        /// <summary>
        /// 初始化缓存
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task IniCache()
        {
            var Personnels = await DBClient.Queryable<Personnel>()
                .LeftJoin<Department>((p, d) => p.DepartmentID == d.DeptID)
                .Select((p, d) => new DTOCachePersonnel
                {
                    PersonnelID = p.PersonnelID,
                    PName = p.PName,
                    DBPCode = p.PCode,
                    CardData = p.CardData,
                    PPassword = p.PPassword,
                    DepartmentID = p.DepartmentID,
                    DeptName = d.DeptName,
                    Job = p.Job,
                    MobilePhone = p.MobilePhone,
                    IdentityCard = p.IdentityCard,
                    Addr = p.Addr,
                    ImageID = p.ImageID
                })
                .ToListAsync();  //ViewOrder是一个新建的类，更多Select用法看下面文档;
            Cache.SetPersonnels(Personnels);

            var Doors = await DBClient.Queryable<Equipment>()
                .LeftJoin<Location>((d, l) => d.LctnID == l.LctnID)
                .Where((d, l) => d.EquptType == FC8280EquptType)
                .Select((d, l) => new DTOCacheDoor
                {
                    EquptID = d.EquptID,
                    EquptSN = d.EquptSN,
                    EquptName = d.EquptName,
                    EquptAddr = d.EquptAddr,
                    LctnID = d.LctnID,
                    LctnName = l.LctnName
                })
                .ToListAsync();  //ViewOrder是一个新建的类，更多Select用法看下面文档;
            Cache.SetDoors(Doors);

            //检查权限
            var DoorDict = Doors.ToDictionary(d => d.EquptID);
            await UpdateAllDoorAccess(DoorDict);

        }

        #region 数据库初始化

        public async Task IniCard3500DBHTTP8280SyncTable()
        {
            string sCreateTableSqlText = @"

if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'HTTP8280SyncTable'))
    drop table [HTTP8280SyncTable];
GO
CREATE TABLE [dbo].[HTTP8280SyncTable](
	[SyncID] [bigint] IDENTITY(1,1) NOT NULL,
	[EquptID] [int] NOT NULL,
	[PersonnelID] [int] NOT NULL,
	[SyncType] [int] NOT NULL,
	[InsertTime] [datetime] NOT NULL,
 CONSTRAINT [PK_HTTP8280SyncTable] PRIMARY KEY CLUSTERED 
(
	[SyncID] ASC
));
GO

ALTER TABLE [dbo].[HTTP8280SyncTable] ADD  CONSTRAINT [DF_HTTP8280SyncTable_InsertTime]  DEFAULT (getdate()) FOR [InsertTime];
GO


GO

if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_EmplOfEqupt_Delete_HTTP8280Sync'))
    drop TRIGGER [tr_EmplOfEqupt_Delete_HTTP8280Sync];
GO
-- =============================================
-- Author:		赖金杰
-- Create date: 2021年12月31日
-- Description:	删除人员权限时同步插入到8280同步表中，标识为权限变更(5)
-- =============================================
CREATE TRIGGER [dbo].[tr_EmplOfEqupt_Delete_HTTP8280Sync] on [dbo].[EmplOfEqupt]
   AFTER Delete
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select EquptID,0,5 from (select Distinct EquptID from deleted) as a

END
GO
if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_EmplOfEqupt_Insert_HTTP8280Sync'))
    drop TRIGGER [tr_EmplOfEqupt_Insert_HTTP8280Sync];
GO
-- =============================================
-- Author:		赖金杰
-- Create date: 2021年12月31日
-- Description:	插入、修改人员权限时同步插入到8280同步表中，标识为权限变更(5)
-- =============================================
CREATE TRIGGER [dbo].[tr_EmplOfEqupt_Insert_HTTP8280Sync] on [dbo].[EmplOfEqupt]
   AFTER insert,update
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select EquptID,0,5 from (select Distinct EquptID from inserted) as a

END

GO
if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_Personnel_Insert_HTTP8280Sync'))
    drop TRIGGER [tr_Personnel_Insert_HTTP8280Sync];
GO

-- =============================================
-- Author:		赖金杰
-- Create date: 2021年12月31日
-- Description:	插入人员时同步插入到8280同步表中，标识为添加、修改人员
-- =============================================
CREATE TRIGGER [dbo].[tr_Personnel_Insert_HTTP8280Sync] on [dbo].[Personnel]
   AFTER INSERT,update
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select 0,PersonnelID,3 from inserted

END
GO

if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_Personnel_Delete_HTTP8280Sync'))
    drop TRIGGER [tr_Personnel_Delete_HTTP8280Sync];
GO
-- =============================================
-- Author:		赖金杰
-- Create date: 2021年12月31日
-- Description:	删除人员时同步插入到8280同步表中，标识为删除人员(4)
-- =============================================
CREATE TRIGGER [dbo].[tr_Personnel_Delete_HTTP8280Sync] on [dbo].[Personnel]
   AFTER Delete
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select 0,PersonnelID,4 from deleted

END

";
            string sSQL = "select count(*) from dbo.[sysObjects] where name ='HTTP8280SyncTable'";
            int iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }
            sSQL = "SELECT count(*) FROM sysObjects where Id=OBJECT_ID(N'tr_Door_Update_HTTP8280Sync')";
            iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                sCreateTableSqlText = @"
if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_Door_Update_HTTP8280Sync'))
    drop TRIGGER [tr_Door_Update_HTTP8280Sync];
GO

-- =============================================
-- Author:		赖金杰
-- Create date: 2022年1月11日
-- Description:	更新设备时同步插入到8280同步表中，标识为更新设备
-- =============================================
CREATE TRIGGER [dbo].[tr_Door_Update_HTTP8280Sync] on [dbo].[Equipment]
   AFTER update
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select EquptID,0,1 from inserted where COMPort <> 255

END

GO

if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'tr_Door_Delete_HTTP8280Sync'))
    drop TRIGGER [tr_Door_Delete_HTTP8280Sync];
GO
-- =============================================
-- Author:		赖金杰
-- Create date: 2022年1月11日
-- Description:	删除设备时同步到FC8280服务器中，删除缓存
-- =============================================
CREATE TRIGGER [dbo].[tr_Door_Delete_HTTP8280Sync] on [dbo].[Equipment]
   AFTER Delete
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	insert into HTTP8280SyncTable (EquptID,PersonnelID,SyncType)
	select EquptID,0,2 from deleted

END
";

                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }

            await CheckCard3500DB_EmplOfEqupt_20220114();

        }

        public async Task CheckCard3500DB_EmplOfEqupt_20220114()
        {
            string sCreateTableSqlText = @"
Alter Table [EmplOfEqupt] add [UploadResult] int null DEFAULT 0;

GO

Alter Table [EmplOfEqupt] add [UploadRepetitionPCode] bigint null DEFAULT 0;

GO

Alter Table [EmplOfEqupt] add [UploadTime] datetime null DEFAULT getdate();

GO
update [EmplOfEqupt] set [UploadResult]=0,[UploadRepetitionPCode]=0,[UploadTime]=getdate();
";
            string sSQL = "SELECT count(*) FROM sys.columns  WHERE Name = N'UploadResult' AND Object_ID = Object_ID(N'EmplOfEqupt')";
            int iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }

            sSQL = "SELECT count(*) FROM sys.columns  WHERE Name = N'UploadTime' AND Object_ID = Object_ID(N'EmplOfEqupt')";
            iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                sCreateTableSqlText = @"
Alter Table [EmplOfEqupt] add [UploadTime] datetime null DEFAULT getdate();

GO
update [EmplOfEqupt] set [UploadTime]=getdate();
";

                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }


            await CheckCard3500DB_AccessEmplDetail_20220120();
        }
        public async Task CheckCard3500DB_AccessEmplDetail_20220120()
        {
            string sCreateTableSqlText = @"
Alter Table [AccessEmplDetail] add [UploadResult] int null DEFAULT 0;

GO

Alter Table [AccessEmplDetail] add [UploadRepetitionPCode] bigint null DEFAULT 0;

GO

Alter Table [AccessEmplDetail] add [UploadTime] datetime null DEFAULT getdate();

GO
update [AccessEmplDetail] set [UploadResult]=0,[UploadRepetitionPCode]=0,[UploadTime]=getdate();
";
            string sSQL = "SELECT count(*) FROM sys.columns  WHERE Name = N'UploadResult' AND Object_ID = Object_ID(N'AccessEmplDetail')";
            int iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }

            await CheckEquipmentTableColumn_20220120();
        }

        public async Task CheckEquipmentTableColumn_20220120()
        {

            string sCreateTableSqlText = @"
ALTER TABLE [Equipment]  add [DriveLanguage] [int] null DEFAULT 1;

GO

ALTER TABLE [Equipment]  add [DriveVolume] [int] null DEFAULT 10;

GO

ALTER TABLE [Equipment]  add [FaceCheckType] [int] null DEFAULT 0;

GO

ALTER TABLE [Equipment]  add [FaceCheckDist] [int] null DEFAULT 2;

GO

ALTER TABLE [Equipment]  add [LightPattern] [int] null DEFAULT 1;

GO

ALTER TABLE [Equipment]  add [SavePhoto] [int] null DEFAULT 1;

GO

ALTER TABLE [Equipment]  add [CheckHelmet] [int] null DEFAULT 0;

GO


ALTER TABLE [Equipment]  add [AuthenticationMode] [int] null DEFAULT 1;


GO


Update [Equipment]  set [DriveLanguage] = 1,[DriveVolume]=10,[FaceCheckType]=0,[FaceCheckDist]=2,[LightPattern]=1,[SavePhoto]=1, [CheckHelmet]=0,AuthenticationMode=1;
";


            //Select count(*) from syscolumns Where  Name = N'DriveLanguage' AND ID=OBJECT_ID('Equipment')
            string sSQL = "SELECT count(*) FROM sys.columns  WHERE Name = N'DriveLanguage' AND Object_ID = Object_ID(N'Equipment')";
            int iCount = await DBClient.Ado.GetIntAsync(sSQL);
            if (iCount == 0)
            {
                string[] sqlList = sCreateTableSqlText.Split("GO", StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in sqlList)
                {
                    await DBClient.Ado.ExecuteCommandAsync(s);
                }
            }
        }

        #endregion



        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task ReloadCache()
        {
            await IniCache();
        }



        #region 同步一卡通数据库操作

        /// <summary>
        /// 同步一卡通数据库的操作
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task SyncDatabase(ILogger log)
        {
            var syncList = await DBClient.Queryable<HTTP8280SyncTable>().OrderBy(d => d.SyncID).ToListAsync();
            if (syncList.Count == 0)
                return;
            var LastSyncID = syncList[syncList.Count - 1].SyncID;//syncList.Max(d => d.SyncID)
            log.LogInformation($"开始同步一卡通数据库操作，同步数量：{syncList.Count},Last SyncID = {LastSyncID}");

            //删除已同步的记录
            await DBClient.Deleteable<HTTP8280SyncTable>()
                .Where(d => d.SyncID <= LastSyncID)
                .ExecuteCommandAsync();

            var q = syncList.GroupBy(t => t.SyncType);
            //同步类型
            //1、 设备属性变更;//2、 删除设备//3、 添加 /修改人员//4、 删除人员//5、 设备权限变更
            IEnumerable<int> equptIDs;
            IEnumerable<int> personnels;

            foreach (var group in q)
            {
                switch (group.Key)
                {
                    case 1://设备属性变更
                        equptIDs = group.Select(d => d.EquptID).Distinct();
                        log.LogInformation($"同步数据库 同步修改门属性 同步数量：{equptIDs.Count()}");
                        await SyncDoorCache(equptIDs);
                        break;
                    case 2://删除设备
                        equptIDs = group.Select(d => d.EquptID).Distinct();
                        log.LogInformation($"同步数据库 同步删除门 同步数量：{equptIDs.Count()}");
                        await SyncDeleteDoorCache(equptIDs);
                        break;
                    case 3://添加 /修改人员
                        personnels = group.Select(d => d.PersonnelID).Distinct();
                        log.LogInformation($"同步数据库 同步修改/新增人员，同步数量：{personnels.Count()}");
                        await SyncPersonnelCache(personnels);
                        break;
                    case 4://删除人员
                        personnels = group.Select(d => d.PersonnelID).Distinct();
                        log.LogInformation($"同步数据库 同步删除人员，同步数量：{personnels.Count()}");
                        await SyncDeletePersonnelCache(personnels);
                        break;
                    case 5://权限变更
                        equptIDs = group.Select(d => d.EquptID).Distinct();
                        log.LogInformation($"同步数据库 同步门权限变更 同步数量：{equptIDs.Count()}");
                        await SyncDoorAccessCache(equptIDs);
                        break;
                    default:
                        break;
                }

            }


        }

        /// <summary>
        /// 同步门缓存
        /// </summary>
        /// <param name="IDList"></param>
        /// <returns></returns>
        private async Task SyncDoorCache(IEnumerable<int> IDList)
        {
            var Doors = await DBClient.Queryable<Equipment>()
                .LeftJoin<Location>((d, l) => d.LctnID == l.LctnID)
                .Where((d, l) => IDList.Contains(d.EquptID))
                .Where((d, l) => d.EquptType == FC8280EquptType)
                .Select((d, l) => new DTOCacheDoor
                {
                    EquptID = d.EquptID,
                    EquptSN = d.EquptSN,
                    EquptName = d.EquptName,
                    EquptAddr = d.EquptAddr,
                    LctnID = d.LctnID,
                    LctnName = l.LctnName
                })
                .ToListAsync();
            Cache.UpdateDoors(Doors);
        }

        /// <summary>
        /// 同步删除门的操作
        /// </summary>
        /// <param name="IDList"></param>
        /// <returns></returns>
        private async Task SyncDeleteDoorCache(IEnumerable<int> IDList)
        {
            Cache.DeleteDoorCacheByDoorIDs(IDList);

            await Task.CompletedTask;
        }

        /// <summary>
        /// 添加修改人员
        /// </summary>
        /// <returns></returns>
        private async Task SyncPersonnelCache(IEnumerable<int> IDList)
        {
            var Personnels = await DBClient.Queryable<Personnel>()
                .LeftJoin<Department>((p, d) => p.DepartmentID == d.DeptID)
                .Where((p, d) => IDList.Contains(p.PersonnelID))
                .Select((p, d) => new DTOCachePersonnel
                {
                    PersonnelID = p.PersonnelID,
                    PName = p.PName,
                    DBPCode = p.PCode,
                    CardData = p.CardData,
                    PPassword = p.PPassword,
                    DepartmentID = p.DepartmentID,
                    DeptName = d.DeptName,
                    Job = p.Job,
                    MobilePhone = p.MobilePhone,
                    IdentityCard = p.IdentityCard,
                    Addr = p.Addr,
                    ImageID = p.ImageID
                })
                .ToListAsync();
            Cache.UpdatePersonnels(Personnels);
        }
        /// <summary>
        /// 同步删除人员的变更
        /// </summary>
        /// <param name="IDList"></param>
        /// <returns></returns>
        private async Task SyncDeletePersonnelCache(IEnumerable<int> IDList)
        {
            Cache.DeletePersonnels(IDList);
            await Task.CompletedTask;
        }

        /// <summary>
        /// 同步门的权限变更
        /// </summary>
        /// <param name="IDList"></param>
        /// <returns></returns>
        private async Task SyncDoorAccessCache(IEnumerable<int> IDList)
        {
            //Dictionary<int, DTOCacheDoor> Doors = new Dictionary<int, DTOCacheDoor>();
            var cacheDoors = Cache.GetDoors();
            Dictionary<int, DTOCacheDoor> Doors = cacheDoors.Values
                                                    .Where(d => IDList.Contains(d.EquptID))
                                                    .ToDictionary(k => k.EquptID);
            await UpdateAllDoorAccess(Doors);
        }
        #endregion



        #endregion

        #region 更新权限统计详情
        /// <summary>
        /// 更新所有门的权限统计数
        /// </summary>
        /// <param name="DoorDict"></param>
        public async Task UpdateAllDoorAccess(Dictionary<int, DTOCacheDoor> DoorDict)
        {
            if (DoorDict.Count == 0) return;
            var EmplOfEqupts = new List<DTOEmplOfEquptTotal>();
            var AccessEmplDetails = new List<DTOAccessEmplDetailTotal>();
            var DeleteCardLists = new List<DTODeleteCardListTotal>();
            #region 读取权限统计列表

            var sIDList = string.Join(',', DoorDict.Keys);

            var sSQL = @$"select EquptID,DownloadState,count(*) as FPDoorCount From EmplOfEqupt where 
PersonnelID in (select PersonnelID from Personnel where IsBlacklist = 0) 
and EquptID  in ({sIDList})
group by EquptID,DownloadState;


select EquptID,isDelete,isUpdate,count(*) as FPDoorCount From AccessEmplDetail where 
PersonnelID in (select PersonnelID from Personnel where IsBlacklist = 0) 
and EquptID  in ({sIDList})
group by EquptID,isDelete,isUpdate;

select EquptID,OptMode,COUNT(*) as FPDoorCount From DeleteCardList
where EquptID  in ({sIDList})
group by EquptID,OptMode,EquptID;";
            var reader = await DBClient.Ado.GetDataReaderAsync(sSQL);

            while (reader.Read())
            {
                var model = new DTOEmplOfEquptTotal()
                {
                    EquptID = reader.GetInt32(0),
                    DownloadState = reader.GetByte(1),
                    AccessCount = reader.GetInt32(2)
                };
                EmplOfEqupts.Add(model);
            }
            reader.NextResult();
            while (reader.Read())
            {
                var model = new DTOAccessEmplDetailTotal()
                {
                    EquptID = reader.GetInt32(0),
                    isDelete = reader.GetByte(1),
                    isUpdate = reader.GetByte(2),
                    AccessCount = reader.GetInt32(3)
                };
                AccessEmplDetails.Add(model);
            }
            reader.NextResult();
            while (reader.Read())
            {
                var model = new DTODeleteCardListTotal()
                {
                    EquptID = reader.GetInt32(0),
                    OptMode = reader.GetInt16(1),
                    AccessCount = reader.GetInt32(2)
                };
                DeleteCardLists.Add(model);
            }
            reader.Close();
            reader.Dispose();
            #endregion

            #region 统计权限
            foreach (var door in DoorDict)
            {
                door.Value.AccessTotal = 0;
                door.Value.NewAccessTotal = 0;
                door.Value.DeleteAccessTotal = 0;
            }

            foreach (var item in EmplOfEqupts)
            {
                var id = item.EquptID;
                if (DoorDict.ContainsKey(id))
                {
                    DTOCacheDoor cacheDoor = DoorDict[id];
                    switch (item.DownloadState)//0--未下载；1--已下载；2--待删除；3--待更新。
                    {
                        case 0:
                        case 3:
                            cacheDoor.NewAccessTotal += item.AccessCount;
                            cacheDoor.AccessTotal += item.AccessCount;
                            break;
                        case 1:
                            cacheDoor.AccessTotal += item.AccessCount;
                            break;
                        case 2:
                            cacheDoor.DeleteAccessTotal += item.AccessCount;
                            break;
                        default:
                            break;
                    }
                }

            }
            foreach (var item in AccessEmplDetails)
            {
                var id = item.EquptID;
                if (DoorDict.ContainsKey(id))
                {
                    DTOCacheDoor cacheDoor = DoorDict[id];
                    if (item.isDelete == 1)
                    {
                        cacheDoor.DeleteAccessTotal += item.AccessCount;
                    }
                    else
                    {
                        if (item.isUpdate == 1)
                        {
                            cacheDoor.NewAccessTotal += item.AccessCount;
                        }
                        cacheDoor.AccessTotal += item.AccessCount;
                    }

                }
            }
            foreach (var item in DeleteCardLists)
            {
                var id = item.EquptID;
                if (DoorDict.ContainsKey(id))
                {
                    DTOCacheDoor cacheDoor = DoorDict[id];
                    switch (item.OptMode)//1--删除，2--挂失，3--黑名单。
                    {
                        case 2:
                        case 3:
                            cacheDoor.NewAccessTotal += item.AccessCount;
                            cacheDoor.AccessTotal += item.AccessCount;
                            break;
                        case 1:
                            cacheDoor.DeleteAccessTotal += item.AccessCount;
                            break;
                        default:
                            break;
                    }

                }
            }
            #endregion
        }

        /// <summary>
        /// 更新单个门的权限统计
        /// </summary>
        /// <param name="door"></param>
        public async Task UpdateDoorAccess(DTOCacheDoor door)
        {
            var doors = new Dictionary<int, DTOCacheDoor>(1);
            doors.Add(door.EquptID, door);
            await UpdateAllDoorAccess(doors);
        }

        #endregion

        #region 打卡记录
        /// <summary>
        /// 保存记录到数据库
        /// </summary>
        /// <param name="record"></param>
        /// <exception cref="NotImplementedException"></exception>
        internal void AddRecord(APIModel_DeviceRecord record)
        {
            if (!RecordCodeConvertTable.ContainsKey(record.EventType)) return;

            //转换为3500的记录格式
            CardRecord cardRecord = new CardRecord();
            cardRecord.CardRecordID = 0;
            cardRecord.PersonnelID = 0;
            cardRecord.EquptID = 0;

            cardRecord.CodeIndex = RecordCodeConvertTable[record.EventType];

            if (record.EventType == 1 || record.EventType == 2)
            {
                if (record.EventType == 1)
                {
                    switch (record.NoteWay)
                    {
                        case 0:// 刷脸
                            cardRecord.CodeIndex = 162;
                            break;
                        case 1:// 刷卡
                            cardRecord.CodeIndex = 0;
                            break;
                        case 2:// 密码
                            cardRecord.CodeIndex = 172;
                            break;
                        default:
                            break;
                    }

                }
                if (record.EventType == 2)
                {
                    switch (record.NoteWay)
                    {
                        case 0:// 刷脸
                            cardRecord.CodeIndex = 212;
                            break;
                        case 1:// 刷卡
                            cardRecord.CodeIndex = 2;
                            break;
                        case 2:// 密码
                            cardRecord.CodeIndex = 2;
                            break;
                        default:
                            break;
                    }

                }
            }

            cardRecord.DataTime = (decimal)record.NoteTime.ToOADate();
            cardRecord.CardData = record.CardNo;
            cardRecord.PortNum = 0;
            cardRecord.PictureID = 0;
            cardRecord.PName = record.EmployeeName;
            cardRecord.PCode = record.EmployeeID.ToString();
            cardRecord.DeptName = "";
            cardRecord.EquptName = "";
            cardRecord.LctnName = "";
            cardRecord.MultiEvent = 0;
            cardRecord.RecordSerialNumber = 0;
            if (record.HumTemp > 33.00 && record.HumTemp < 50.00)
                cardRecord.BodyTemperature = (int)(record.HumTemp * 100);


            //正常通行时，判断是否为人脸识别
            if (record.EventType == 1)
            {
                switch (record.NoteWay)
                {
                    case 0://刷脸
                        cardRecord.CodeIndex = 162;//人脸识别
                        break;
                    case 2://密码验证
                        cardRecord.CodeIndex = 4;//密码开门
                        break;
                    default:
                        break;
                }

            }

            #region 查询人员
            //查询人员
            var pCodes = Cache.GetPersonnelCodes();
            long PCode = record.EmployeeID;
            if (pCodes.ContainsKey(PCode))
            {
                var people = pCodes[PCode];
                cardRecord.PersonnelID = people.PersonnelID;
                cardRecord.PName = people.PName;
                cardRecord.DeptName = people.DeptName;
                cardRecord.PCode = people.DBPCode;
            }
            #endregion

            #region 查询设备
            //查询设备
            string sn = record.DeviceID;

            DTOCacheDoor device = Cache.GetDoor(sn);
            if (device != null)
            {
                cardRecord.EquptID = device.EquptID;
                cardRecord.PortNum = (byte)(device.EquptAddr + 1);
                cardRecord.EquptName = device.EquptName;
                cardRecord.LctnName = device.LctnName;
            }
            #endregion

            if (string.IsNullOrEmpty(cardRecord.PName)) cardRecord.PName = string.Empty;
            if (string.IsNullOrEmpty(cardRecord.DeptName)) cardRecord.DeptName = string.Empty;

            if (string.IsNullOrEmpty(cardRecord.LctnName)) cardRecord.LctnName = string.Empty;
            if (string.IsNullOrEmpty(cardRecord.EquptName)) cardRecord.EquptName = string.Empty;

            if (record.Pic_Len > 0 && !string.IsNullOrEmpty(record.ImgURL))
            {
                //有照片需要保存
                RecordImage image = new RecordImage();
                image.RecordDate = cardRecord.DataTime;
                image.PicImage = Encoding.Default.GetBytes(record.ImgURL);
                image.AVIID = 0;
                image.RecordImageID = DBClient.Insertable(image).ExecuteReturnIdentity();
                cardRecord.PictureID = image.RecordImageID;
            }

            cardRecord.CardRecordID = DBClient.Insertable(cardRecord).ExecuteReturnIdentity();
            //throw new NotImplementedException();

            //增加区域判断

        }
        #endregion

        #region 添加人员


        #region 获取待上传人员名单
        /// <summary>
        /// 从数据库中获取需要上传到人脸机的人员
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task<List<APIModel_DevicePeople>> GetDoorAccess(DTOCacheDoor oDoor, int limit)
        {
            Dictionary<int, APIModel_DevicePeople> AccessPeoples = new Dictionary<int, APIModel_DevicePeople>(limit);
            List<DTOCacheUploadPeople> UploadPeopleCache = new List<DTOCacheUploadPeople>();
            #region 查询待删除列表
            await QueryDeleteCardListTable(oDoor, limit, AccessPeoples, UploadPeopleCache);
            #endregion
            #region 查询权限组
            await QueryAccessEmplDetailTable(oDoor, limit, AccessPeoples, UploadPeopleCache);
            #endregion
            #region 查询个人权限
            await QueryEmplOfEquptTable(oDoor, limit, AccessPeoples, UploadPeopleCache);
            #endregion

            if (AccessPeoples.Count > 0)
            {
                //缓存上传的人员编号
                oDoor.UploadPersonnelCache = UploadPeopleCache;
                return AccessPeoples.Values.ToList();
            }
            else
                return null;
        }
        #region 查询途径
        /// <summary>
        /// 从待删除表加载挂失或黑名单人员
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryDeleteCardListTable(DTOCacheDoor oDoor, int limit,
            Dictionary<int, APIModel_DevicePeople> AccessPeoples,
            List<DTOCacheUploadPeople> UploadPeopleCache)
        {

            if (AccessPeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelCodes();
            limit = limit - AccessPeoples.Count;
            var deleteCardLists = await DBClient.Queryable<DeleteCardList>()
           .Where(aed => aed.EquptID == oDoor.EquptID && (aed.OptMode == 2 || aed.OptMode == 3))
           .OrderBy(a => a.CardData)
           .ToPageListAsync(1, limit);
            if (deleteCardLists.Count > 0)
            {
                foreach (var item in deleteCardLists)
                {
                    if (personnels.ContainsKey(item.CardData))
                    {
                        var personnel = personnels[item.CardData];

                        if (!AccessPeoples.ContainsKey(personnel.PersonnelID))
                        {
                            var access = new APIModel_DevicePeople();

                            PersonnelToAPIAccessModel(access, personnel);
                            access.EmployeeRoot = 3;

                            access.TimegroupID = 1;

                            var dDeadline = DateTime.Now.AddYears(60);
                            access.DevicePassBean.SetAccessDeadline(dDeadline);
                            access.DevicePassBean.DevicePassNumber = 0;

                            UploadPeopleCache.Add(new DTOCacheUploadPeople()
                            {
                                AccessID = personnel.PCode,
                                Personnel = personnel,
                                TableName = "DeleteCardList"
                            }); ;

                            AccessPeoples.Add(personnel.PersonnelID, access);
                        }

                    }

                }
            }

        }

        /// <summary>
        /// 从权限组获取权限
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryAccessEmplDetailTable(DTOCacheDoor oDoor, int limit,
            Dictionary<int, APIModel_DevicePeople> AccessPeoples,
            List<DTOCacheUploadPeople> UploadPeopleCache)
        {
            if (AccessPeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelIDs();
            limit = limit - AccessPeoples.Count;
            //先查询权限组
            var accessGroups = await DBClient.Queryable<AccessEmplDetail>()
                .InnerJoin<Personnel>((aed, per) => aed.PersonnelID == per.PersonnelID)
                .Where(aed => aed.EquptID == oDoor.EquptID && aed.IsUpdate != 0 && aed.IsDelete == 0)
                .IgnoreColumns(a => a.IsDelete)
                .IgnoreColumns(a => a.IsUpdate)
                .IgnoreColumns(a => a.IsUpload)
                .IgnoreColumns(a => a.HldPwr)
                .IgnoreColumns(a => a.HldEnabled)
                .IgnoreColumns(a => a.CardMode)
                .OrderBy(aed => aed.PersonnelID)
                .ToPageListAsync(1, limit);
            if (accessGroups.Count > 0)
            {
                foreach (var item in accessGroups)
                {
                    if (personnels.ContainsKey(item.PersonnelID))
                    {
                        if (!AccessPeoples.ContainsKey(item.PersonnelID))
                        {
                            var access = new APIModel_DevicePeople();
                            var personnel = personnels[item.PersonnelID];

                            PersonnelToAPIAccessModel(access, personnel);

                            access.TimegroupID = item.TimePieceIndex;
                            var dDeadline = DateTime.FromOADate((double)item.PermitTime);
                            access.DevicePassBean.SetAccessDeadline(dDeadline);
                            if (item.ReadCount != 65535)
                                access.DevicePassBean.DevicePassNumber = item.ReadCount;

                            UploadPeopleCache.Add(new DTOCacheUploadPeople()
                            {
                                AccessID = item.DetailID,
                                Personnel = personnel,
                                TableName = "AccessEmplDetail"

                            });
                            AccessPeoples.Add(item.PersonnelID, access);

                        }

                    }

                }
            }
        }

        /// <summary>
        /// 从个人权限表获取权限
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryEmplOfEquptTable(DTOCacheDoor oDoor, int limit,
            Dictionary<int, APIModel_DevicePeople> AccessPeoples,
            List<DTOCacheUploadPeople> UploadPeopleCache)
        {
            if (AccessPeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelIDs();
            limit = limit - AccessPeoples.Count;
            //先查询权限组
            var accessGroups = await DBClient.Queryable<EmplOfEqupt>()
                .InnerJoin<Personnel>((eoe, per) => eoe.PersonnelID == per.PersonnelID)
                .Where(eoe => eoe.EquptID == oDoor.EquptID && (eoe.DownloadState == 0 || eoe.DownloadState == 3))
                .IgnoreColumns(a => a.EquptID)
                .IgnoreColumns(a => a.OpenLock)
                .IgnoreColumns(a => a.CardMode)
                .IgnoreColumns(a => a.HldEnabled)
                .IgnoreColumns(a => a.HldPwr)
                .IgnoreColumns(a => a.DownloadState)
                .IgnoreColumns(a => a.InoutstatePort1)
                .IgnoreColumns(a => a.InoutstatePort2)
                .IgnoreColumns(a => a.InoutstatePort3)
                .IgnoreColumns(a => a.InoutstatePort4)
                .IgnoreColumns(a => a.InoutstateDatePort1)
                .IgnoreColumns(a => a.InoutstateDatePort2)
                .IgnoreColumns(a => a.InoutstateDatePort3)
                .IgnoreColumns(a => a.InoutstateDatePort4)
                .OrderBy(eoe => eoe.PersonnelID)
                .ToPageListAsync(1, limit);
            if (accessGroups.Count > 0)
            {
                foreach (var item in accessGroups)
                {
                    if (personnels.ContainsKey(item.PersonnelID))
                    {
                        if (!AccessPeoples.ContainsKey(item.PersonnelID))
                        {
                            var access = new APIModel_DevicePeople();
                            var personnel = personnels[item.PersonnelID];

                            PersonnelToAPIAccessModel(access, personnel);

                            if (item.UserType.HasValue)
                                access.EmployeeRoot = item.UserType.Value;

                            access.TimegroupID = item.TimePieceIndex[0];
                            var dDeadline = DateTime.FromOADate((double)item.PermitTime);
                            access.DevicePassBean.SetAccessDeadline(dDeadline);
                            if (item.ReadCount != 65535)
                                access.DevicePassBean.DevicePassNumber = item.ReadCount;

                            UploadPeopleCache.Add(new DTOCacheUploadPeople()
                            {
                                AccessID = item.EmplOfEquptID,
                                Personnel = personnel,
                                TableName = "EmplOfEqupt"
                            });
                            AccessPeoples.Add(item.PersonnelID, access);
                        }

                    }

                }
            }
        }

        /// <summary>
        /// 将人员信息转换为人脸机权限信息
        /// </summary>
        /// <param name="access"></param>
        /// <param name="personnel"></param>
        private void PersonnelToAPIAccessModel(APIModel_DevicePeople access, DTOCachePersonnel personnel)
        {
            access.EmployeeID = personnel.PCode;
            access.EmployeeName = personnel.PName;
            access.EmployeeJob = personnel.Job;
            access.EmployeePhone = personnel.MobilePhone;
            access.EmployeeIdentity = personnel.IdentityCard;
            access.EmployeeAddress = personnel.Addr;
            access.EmployeePassword = personnel.PPassword;
            access.EmployeeIc = personnel.CardData;
            access.EmployeeShold = 0;
            access.EmployeeRoot = 0;

            if (personnel.ImageID > 0 && personnel.ImageSize == 0)
            {
                lock (lockObject)
                {
                    if (personnel.ImageID > 0 && personnel.ImageSize == 0)
                    {
                        //从数据库加载人员照片
                        var imageModel = DBClient.Queryable<PicImage>().Where(p => p.PictureID == personnel.ImageID).First();
                        if (imageModel != null)
                        {

                            var sFilePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "personnelimage");
                            try
                            {
                                if (!Directory.Exists(sFilePath))
                                    Directory.CreateDirectory(sFilePath);
                                var sfileName = Path.Combine(sFilePath, $"{personnel.PCode}.jpg");
                                if (File.Exists(sfileName))
                                    File.Delete(sfileName);
                                File.WriteAllBytes(sfileName, imageModel.PicImageBuf);
                                personnel.ImageSize = imageModel.PicImageBuf.Length;
                                var md5 = MD5Helper.GetByteBufMD5(imageModel.PicImageBuf);
                                personnel.ImageURL = $"/personnelimage/{personnel.PCode}.jpg?md5={HttpUtility.UrlEncode(md5)}";
                                personnel.ImageMD5 = md5;
                            }
                            catch (Exception)
                            {
                                //log4net.Error();
                                //更新人员照片失败
                                return;
                            }

                        }
                        else
                        {
                            personnel.ImageID = 0;
                            personnel.ImageSize = 0;
                            personnel.ImageMD5 = string.Empty;
                        }
                    }
                }


            }
            if (personnel.ImageSize > 0)
            {
                access.EmployeePhotoWay = "path";
                access.PhotoMD5 = personnel.ImageMD5;
                access.EmployeePhoto = personnel.ImageURL;
            }

        }

        #endregion
        #endregion


        #region 保存人员上传结果

        /// <summary>
        /// 上传错误代码表，这些代码需要过滤
        /// </summary>
        private HashSet<int> FilterUploadFailErrCodeHash = new HashSet<int>() {
            7,//图像解码失败
            8,//图像拷贝出错
            10,//人员信息写入数据库失败
            15,//应用程序内部错误
            19,//人脸注册校验失败
            20,//Json 数据解析出错
        };

        /// <summary>
        /// 保存上传人员的结果
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="failNumber"></param>
        /// <param name="failEmployeeId"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task SaveDoorAccessUploadResult(DTOCacheDoor oDoor, int failNumber, FailPeopleDetail[] failEmployeeId)
        {
            if (oDoor.UploadPersonnelCache == null)
                return;
            //记录日志
            if (failNumber > 0 && failEmployeeId != null)
            {
                //错误的日志
                foreach (var failItem in failEmployeeId)
                {
                    if (FilterUploadFailErrCodeHash.Contains(failItem.ErrorCode))
                    {
                        oDoor.UploadPersonnelCache.RemoveAll((x) => x.Personnel.PCode == failItem.EmployeeID);
                    }
                    else
                    {
                        var cacheAccessPeople = oDoor.UploadPersonnelCache.FirstOrDefault((x) => x.Personnel.PCode == failItem.EmployeeID);
                        cacheAccessPeople.result = failItem.ErrorCode;
                        cacheAccessPeople.repetitionPCode = failItem.RepeatID;
                    }
                }


            }

            await SavePersonnelAccessUploadResultByDeleteCardList(oDoor);
            await SavePersonnelAccessUploadResultByAccessEmplDetail(oDoor);
            await SavePersonnelAccessUploadResultByEmplOfEqupt(oDoor);
            oDoor.UploadPersonnelCache = null;
            //更新权限信息
            await UpdateDoorAccess(oDoor);

        }

        /// <summary>
        /// 保存待删除表中的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SavePersonnelAccessUploadResultByDeleteCardList(DTOCacheDoor oDoor)
        {
            var UploadPeopleCache = oDoor.UploadPersonnelCache;
            var uploads = UploadPeopleCache.Where(u => u.TableName == "DeleteCardList").ToList();
            if (uploads.Count == 0) return;
            long[] Cards = uploads.Select(u => u.AccessID).ToArray();
            await DBClient.Deleteable<DeleteCardList>()
                .Where(d => d.EquptID == oDoor.EquptID)
                .In(d => d.CardData, Cards)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 更新权限组的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SavePersonnelAccessUploadResultByAccessEmplDetail(DTOCacheDoor oDoor)
        {
            var UploadPeopleCache = oDoor.UploadPersonnelCache;
            var uploads = UploadPeopleCache.Where(u => u.TableName == "AccessEmplDetail").ToList();
            if (uploads.Count == 0) return;
            int[] ids = uploads.Select(u => (int)u.AccessID).ToArray();

            var idsOKList = uploads.Where(u => u.result == 0).Select(u => u.AccessID).ToArray();
            if (idsOKList.Length > 0)
            {
                await DBClient.Updateable<AccessEmplDetail>()
                .SetColumns(d => d.IsUpdate == 0)
                .SetColumns(d => d.IsUpload == 1)
                .SetColumns(d => d.UploadResult == 0)
                .SetColumns(d => d.UploadRepetitionPCode == 0)
                .SetColumns(d => d.UploadTime == DateTime.Now)
                .Where(d => idsOKList.Contains(d.DetailID))
                .ExecuteCommandAsync();

                uploads.RemoveAll(u => idsOKList.Contains(u.AccessID));
            }

            if (uploads.Count > 0)
            {
                foreach (var item in uploads)
                {
                    await DBClient.Updateable<AccessEmplDetail>()
                    .SetColumns(d => d.IsUpdate == 0)
                    .SetColumns(d => d.IsUpload == 1)
                    .SetColumns(d => d.UploadResult == item.result)
                    .SetColumns(d => d.UploadRepetitionPCode == item.repetitionPCode)
                    .SetColumns(d => d.UploadTime == DateTime.Now)
                    .Where(d => d.DetailID == item.AccessID)
                    .ExecuteCommandAsync();
                }
            }
        }

        /// <summary>
        /// 更新个人权限表的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SavePersonnelAccessUploadResultByEmplOfEqupt(DTOCacheDoor oDoor)
        {
            var UploadPeopleCache = oDoor.UploadPersonnelCache;
            var uploads = UploadPeopleCache.Where(u => u.TableName == "EmplOfEqupt").ToList();
            if (uploads.Count == 0) return;
            long[] ids = uploads.Select(u => u.AccessID).ToArray();


            var idsOKList = uploads.Where(u => u.result == 0).Select(u => u.AccessID).ToArray();
            if (idsOKList.Length > 0)
            {
                await DBClient.Updateable<EmplOfEqupt>()
                .SetColumns(d => d.DownloadState == 1)
                .SetColumns(d => d.UploadResult == 0)
                .SetColumns(d => d.UploadRepetitionPCode == 0)
                .SetColumns(d => d.UploadTime == DateTime.Now)
                .Where(d => idsOKList.Contains(d.EmplOfEquptID))
                .ExecuteCommandAsync();

                uploads.RemoveAll(u => idsOKList.Contains(u.AccessID));
            }

            if (uploads.Count > 0)
            {
                foreach (var item in uploads)
                {
                    await DBClient.Updateable<EmplOfEqupt>()
                    .SetColumns(d => d.DownloadState == 1)
                    .SetColumns(d => d.UploadResult == item.result)
                    .SetColumns(d => d.UploadRepetitionPCode == item.repetitionPCode)
                    .SetColumns(d => d.UploadTime == DateTime.Now)
                    .Where(d => d.EmplOfEquptID == item.AccessID)
                    .ExecuteCommandAsync();
                }
            }
        }
        #endregion

        #endregion


        #region 删除人员

        #region 获取待删除的人员名单
        /// <summary>
        /// 从数据库中获取需要删除的人员
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task<List<PeopleResultDetail>> GetDoorAccessByDelete(DTOCacheDoor oDoor, int limit)
        {
            Dictionary<long, PeopleResultDetail> DeletePeoples = new Dictionary<long, PeopleResultDetail>(limit);
            List<DTOCacheUploadPeople> DeletePeopleCache = new List<DTOCacheUploadPeople>();
            #region 查询待删除列表
            await QueryDeleteCardListTableByDelete(oDoor, limit, DeletePeoples, DeletePeopleCache);
            #endregion
            #region 查询权限组
            await QueryAccessEmplDetailTableByDelete(oDoor, limit, DeletePeoples, DeletePeopleCache);
            #endregion
            #region 查询个人权限
            await QueryEmplOfEquptTableByDelete(oDoor, limit, DeletePeoples, DeletePeopleCache);
            #endregion

            if (DeletePeoples.Count > 0)
            {
                //缓存删除的人员编号
                oDoor.DeletePersonnelCache = DeletePeopleCache;
                return DeletePeoples.Values.ToList();
            }
            else
                return null;
        }
        #region 查询途径
        /// <summary>
        /// 从待删除表加载待删除的人员编号
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryDeleteCardListTableByDelete(DTOCacheDoor oDoor, int limit,
            Dictionary<long, PeopleResultDetail> DeletePeoples,
            List<DTOCacheUploadPeople> DeletePeopleCache)
        {

            if (DeletePeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelCodes();
            limit = limit - DeletePeoples.Count;
            var deleteCardLists = await DBClient.Queryable<DeleteCardList>()
           .Where(aed => aed.EquptID == oDoor.EquptID && aed.OptMode == 1)
           .OrderBy(a => a.CardData)
           .ToPageListAsync(1, limit);
            if (deleteCardLists.Count > 0)
            {
                foreach (var item in deleteCardLists)
                {
                    var access = new PeopleResultDetail();


                    access.EmployeeID = item.CardData;


                    DeletePeopleCache.Add(new DTOCacheUploadPeople()
                    {
                        AccessID = item.CardData,
                        TableName = "DeleteCardList"
                    }); ;

                    DeletePeoples.Add(item.CardData, access);




                }
            }

        }

        /// <summary>
        /// 从权限组获取待删除的权限
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryAccessEmplDetailTableByDelete(DTOCacheDoor oDoor, int limit,
            Dictionary<long, PeopleResultDetail> DeletePeoples,
            List<DTOCacheUploadPeople> DeletePeopleCache)
        {
            if (DeletePeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelIDs();
            limit = limit - DeletePeoples.Count;
            //先查询权限组
            var accessGroups = await DBClient.Queryable<AccessEmplDetail>()
                .Where(aed => aed.EquptID == oDoor.EquptID && aed.IsDelete != 0)
                .Select(a => new { a.DetailID, a.PersonnelID })
                .OrderBy(a => a.PersonnelID)
                .ToPageListAsync(1, limit);
            if (accessGroups.Count > 0)
            {
                foreach (var item in accessGroups)
                {
                    if (personnels.ContainsKey(item.PersonnelID))
                    {
                        var personnel = personnels[item.PersonnelID];
                        long pCode = personnel.PCode;
                        if (!DeletePeoples.ContainsKey(pCode))
                        {
                            var access = new PeopleResultDetail();

                            access.EmployeeID = pCode;


                            DeletePeopleCache.Add(new DTOCacheUploadPeople()
                            {
                                AccessID = item.DetailID,
                                Personnel = personnel,
                                TableName = "AccessEmplDetail"

                            });
                            DeletePeoples.Add(pCode, access);

                        }

                    }

                }
            }
        }

        /// <summary>
        /// 从个人权限表获取待删除的权限
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="limit"></param>
        /// <param name="AccessPeoples"></param>
        /// <returns></returns>
        private async Task QueryEmplOfEquptTableByDelete(DTOCacheDoor oDoor, int limit,
            Dictionary<long, PeopleResultDetail> DeletePeoples,
            List<DTOCacheUploadPeople> DeletePeopleCache)
        {
            if (DeletePeoples.Count >= limit) return;
            var personnels = Cache.GetPersonnelIDs();
            limit = limit - DeletePeoples.Count;
            //先查询权限组
            var accessGroups = await DBClient.Queryable<EmplOfEqupt>()
                .Where(aed => aed.EquptID == oDoor.EquptID && aed.DownloadState == 2)
                .Select(a => new { a.EmplOfEquptID, a.PersonnelID })
                .OrderBy(a => a.PersonnelID)
                .ToPageListAsync(1, limit);
            if (accessGroups.Count > 0)
            {
                foreach (var item in accessGroups)
                {
                    if (personnels.ContainsKey(item.PersonnelID))
                    {
                        var personnel = personnels[item.PersonnelID];
                        long pCode = personnel.PCode;
                        if (!DeletePeoples.ContainsKey(pCode))
                        {
                            var access = new PeopleResultDetail();
                            access.EmployeeID = pCode;

                            DeletePeopleCache.Add(new DTOCacheUploadPeople()
                            {
                                AccessID = item.EmplOfEquptID,
                                Personnel = personnel,
                                TableName = "EmplOfEqupt"
                            });
                            DeletePeoples.Add(pCode, access);
                        }

                    }

                }
            }
        }



        #endregion
        #endregion

        #region 保存删除结果
        /// <summary>
        /// 将从人脸机上删除的人员，从数据库删除
        /// </summary>
        /// <param name="oDoor"></param>
        /// <param name="deleteAll"></param>
        /// <returns></returns>
        internal async Task SaveDoorAccessDeleteResult(DTOCacheDoor oDoor, int deleteAll)
        {

            if (deleteAll != 0)
            {
                //删除所有待删除的权限
                await SaveDoorAccessDeleteResultByDeleteALL(oDoor);
            }
            else
            {
                if (oDoor.DeletePersonnelCache == null)
                    return;
                await SaveDoorAccessDeleteResultByDeleteCardList(oDoor);
                await SaveDoorAccessDeleteResultByAccessEmplDetail(oDoor);
                await SaveDoorAccessDeleteResultByEmplOfEqupt(oDoor);
                oDoor.DeletePersonnelCache = null;

            }
            //更新权限信息
            await UpdateDoorAccess(oDoor);

        }

        /// <summary>
        /// 人脸机中已删除了所有权限
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SaveDoorAccessDeleteResultByDeleteALL(DTOCacheDoor oDoor)
        {
            var sSQL = @$"
Delete from DeleteCardList where EquptID = {oDoor.EquptID} and OptMode = 1;


Delete from EmplOfEqupt where EquptID = {oDoor.EquptID} and DownloadState = 2;
Update EmplOfEqupt set DownloadState=0 where EquptID = {oDoor.EquptID} and DownloadState in (1,3);

Delete from AccessEmplDetail where EquptID = {oDoor.EquptID} and isDelete <> 0;
Update AccessEmplDetail set isUpload=0,isUpdate=1 where EquptID = {oDoor.EquptID} and (isUpload = 1 or isUpdate= 0)  ;

";
            await DBClient.Ado.ExecuteCommandAsync(sSQL, (object)null);

        }
        /// <summary>
        /// 保存待删除表中的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SaveDoorAccessDeleteResultByDeleteCardList(DTOCacheDoor oDoor)
        {
            var DeletePersonnelCache = oDoor.DeletePersonnelCache;
            var deletes = DeletePersonnelCache.Where(u => u.TableName == "DeleteCardList").ToList();
            if (deletes.Count == 0) return;
            long[] Cards = deletes.Select(u => u.AccessID).ToArray();
            if (Cards.Length == 0) return;

            await DBClient.Deleteable<DeleteCardList>()
                .Where(d => d.EquptID == oDoor.EquptID)
                .In(d => d.CardData, Cards)
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 更新权限组的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SaveDoorAccessDeleteResultByAccessEmplDetail(DTOCacheDoor oDoor)
        {
            var DeletePersonnelCache = oDoor.DeletePersonnelCache;
            var deletes = DeletePersonnelCache.Where(u => u.TableName == "AccessEmplDetail").ToList();
            if (deletes.Count == 0) return;
            int[] ids = deletes.Select(u => (int)u.AccessID).ToArray();
            await DBClient.Deleteable<AccessEmplDetail>()
                .Where(d => ids.Contains(d.DetailID))
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 更新个人权限表的上传信息
        /// </summary>
        /// <param name="oDoor"></param>
        /// <returns></returns>
        private async Task SaveDoorAccessDeleteResultByEmplOfEqupt(DTOCacheDoor oDoor)
        {
            var DeletePersonnelCache = oDoor.DeletePersonnelCache;
            var deletes = DeletePersonnelCache.Where(u => u.TableName == "EmplOfEqupt").ToList();
            if (deletes.Count == 0) return;
            long[] ids = deletes.Select(u => u.AccessID).ToArray();
            await DBClient.Deleteable<EmplOfEqupt>()
                .Where(d => ids.Contains(d.EmplOfEquptID))
                .ExecuteCommandAsync();

        }
        #endregion
        #endregion


        #region 工作参数
        /// <summary>
        /// 保存设备参数
        /// </summary>
        /// <param name="par"></param>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task SaveDoorWorkParameter(APIModel_WorkParameter par)
        {
            //throw new NotImplementedException();
            string SN = par.DeviceID;
            DTOCacheDoor cacheDoor = Cache.GetDoor(SN);
            if (cacheDoor == null)
            {
                lock (lockObject)
                {
                    cacheDoor = Cache.GetDoor(SN);
                    if (cacheDoor == null)
                    {
                        InsertDoor(par);
                        return;
                    }
                }
            }

            Equipment Door = await DBClient.Queryable<Equipment>().Where(it => it.EquptID == cacheDoor.EquptID).FirstAsync();
            WorkParameterToDoor(par, Door);
            Door.COMPort = 255;
            await DBClient.Updateable(Door).ExecuteCommandAsync();

            cacheDoor.WorkParameter = par;
            cacheDoor.EquptAddr = Door.EquptAddr;
            cacheDoor.EquptName = Door.EquptName;
            cacheDoor.LctnID = Door.LctnID;
            cacheDoor.OnlineTime = DateTime.Now;

            Cache.SetDoor(cacheDoor);
        }

        /// <summary>
        /// 将设备参数转换为一卡通软件中的数据库表结构
        /// </summary>
        /// <param name="par"></param>
        /// <param name="Door"></param>
        private void WorkParameterToDoor(APIModel_WorkParameter par, Equipment Door)
        {
            //设备名称
            if (!string.IsNullOrEmpty(par.ParameterCompanyName))
            {
                Door.EquptName = par.ParameterCompanyName;
                Door.ScreenShowName = 1;
            }
            else
                Door.ScreenShowName = 0;

            //版本号

            if (!string.IsNullOrEmpty(par.ParameterFirmwareMsg))
            {
                var ver = par.ParameterFirmwareMsg.Replace("Ver", string.Empty).Trim();
                Door.EquptVer = float.Parse(ver);
            }



            Door.EquptStatus = 1;//在线状态


            #region 系统参数

            //语言选择 0，中文；1，英文；2，繁体
            Door.DriveLanguage = par.ParameterLanguageChoose;
            //设备音量  0-10；0--关闭声音；10--最大声音
            Door.DriveVolume = par.ParameterVolume;

            //语音模式 0,不播报；1，播放名字; 2,播放问候语;3,播放名字和问候语
            Door.DoorWork[0] = (byte)par.ParameterVoiceMode;

            //陌生人语音 0，不播报;1,播报假体;2，播报陌生人；3，播报假体和陌生人
            Door.DoorWork[1] = (byte)par.ParameterStrangerVoice;

            //问候语 0，请通行;1,欢迎光临;2，时间问候语
            Door.DoorWork[2] = (byte)par.ParameterGrettings;

            //亮度设置 1-10
            Door.DoorWork[3] = (byte)par.ParameterBrightness;

            //曝光设置 -3-3
            Door.DoorWork[4] = (byte)(par.ParameterExposure + 10);


            #region KeypadPar 菜单管理密码
            if (!string.IsNullOrWhiteSpace(par.ParameterLoginPassword))
            {
                Door.KeypadPar = ModTool.HexToByte(FillString(par.ParameterLoginPassword, 10));
            }
            else
            {
                Door.KeypadPar = new byte[1] { 0xFF };//表示没有密码
            }
            #endregion

            // 红外图像开关 0--关闭；1--开启
            Door.DoorWork[5] = (byte)par.ParameterIR;
            #endregion

            #region 门禁参数
            //WG输出字节


            //parameterAccessType |出入类型 0,入门；1，出门
            Door.EquptAddr = par.ParameterAccessType;

            //parameterWgFormat  WG输出格式 26 / 34
            Door.ReaderByte = (byte)(par.ParameterWgFormat == 26 ? 3 : 4);

            //parameterKeepOpenDoor --开门保持时间 1-65535（s）
            Door.OpenDoorTime = par.ParameterKeepOpenDoor;

            #region 识别间隔参数
            Door.ReaderInterval = new byte[2] { 1, (byte)par.ParameterIntervalRecoSwitch };
            var timeArr = ModTool.Int32To2Byte(par.ParameterRecgInterval);
            Door.SystemPar[17] = timeArr[0];
            Door.SystemPar[18] = timeArr[1];
            #endregion
            //自由通行（免验证）0--禁止；1--启用
            #region ProhibitCheck 全卡开门参数
            Door.ProhibitCheck = new byte[3];
            Door.ProhibitCheck[0] = (byte)par.ParameterLaissezSwitch;
            #endregion
            #endregion

            #region 报警参数

            //消防报警功能开关 0--禁用；1--启用, 禁用之后报警就不会触发
            Door.FireAlarm = par.ParameterFireAlarm;


            //开门超时报警功能
            #region LongOpenAlarm 开门超时提示参数
            Door.LongOpenAlarm = new byte[4];
            Door.LongOpenAlarm[0] = (byte)par.ParameterDoorLongOpenAlarmSwitch;
            Door.LongOpenAlarm[1] = 0;
            Door.LongOpenAlarm[2] = (byte)par.ParameterDoorSensorDelay;
            Door.LongOpenAlarm[3] = 1;
            #endregion


            //门磁报警功能
            #region DoorStateAlarm 门磁报警参数
            Door.DoorStateAlarm = new byte[225];
            Door.DoorStateAlarm[0] = (byte)par.ParameterDoorAlarmSwitch;
            #endregion
            #endregion

            #region 人脸识别
            //人脸识别阈值 1-99
            Door.FaceRecognitionThreshold = (byte)par.ParameterFaceThreshold;

            //识别距离
            Door.FaceCheckDist = par.ParameterDistance;

            //活体检测
            Door.FaceCheckType = par.ParameterPreview;

            //活体检测阈值 1-99
            Door.FaceBioassaySimilarity = par.ParameterFaceIRThreshold;

            //补光灯模式  ；0--一直关 1--一直亮；2--检测到人员时开
            Door.FaceLEDMode = (byte)par.ParameterLightSwitch;

            //口罩识别开关 0--禁止；1--启用
            Door.FaceMouthmufflePar = (byte)par.ParameterMask;

            //口罩识别阈值： 1-99
            Door.DoorWork[6] = (byte)par.ParameterMaskThreshold;

            #region  BodyTemperaturePar 体温检测开关及格式
            if (par.ParameterTempSwitch == 1)
            {
                if (par.ParameterFahrenheitSwitch == 1)
                {
                    Door.BodyTemperaturePar = 2;
                }
                else
                    Door.BodyTemperaturePar = 1;

                Door.BodyTemperatureAlarmPar = (int)(par.ParameterTempThresholdMax * 10);
            }
            else
            {
                Door.BodyTemperaturePar = 0;
                Door.BodyTemperatureAlarmPar = 375;
            }
            #endregion

            //打卡现场照片保存开关
            Door.SavePhoto = par.ParameterSavePicture;
            #endregion


            #region 其他功能
            //是否存储陌生人记录，0:不存储，1:存储
            Door.DoorWork[7] = (byte)par.ParameterSaveExternalvisitors;
            #endregion

            #region 网络参数
            Door.IPAddr = par.ParameterNetworkIpUrl;

            #region TCPPar TCP参数
            TCPInfo_Door8000 tcp = new TCPInfo_Door8000();
            tcp.MAC = "00-18-00-00-00-00";
            tcp.DNSBuckup = "0.0.0.0";
            tcp.TCPPort = 8000;
            tcp.UDPPort = 8101;
            tcp.ServerPort = 0;
            tcp.ServerIP = "0.0.0.0";
            tcp.ServerAddr = par.ParameterCloudserverAddress;
            //if (par.ParameterNetworkSwitch == 1)
            //{
            tcp.AutoIP = par.ParameterNetworkIpActive == 1;
            //有线网络
            tcp.IP = par.ParameterNetworkIpUrl;
            tcp.IPMask = par.ParameterNetworkSubnetMask;
            tcp.IPGateway = par.ParameterNetworkGteway;
            tcp.DNS = par.ParameterNetworkDns;

            Door.TCPPar = tcp.GetBytes();
            #endregion

            //调试开关 0-关闭；1-打开
            if (!par.ParameterEnableTelnet.HasValue) par.ParameterEnableTelnet = 0;
            Door.DoorWork[8] = (byte)par.ParameterEnableTelnet.Value;

            //web登陆开关 0-关闭；1-打开
            if (!par.ParameterEnableWeb.HasValue) par.ParameterEnableWeb = 1;
            Door.DoorWork[9] = (byte)par.ParameterEnableWeb.Value;

            //UDP端口号 （UDP广播搜索发现用）
            if (!par.ParameterUDPPort.HasValue) par.ParameterUDPPort = 8101;
            var portBytes = ModTool.Int32To2Byte(par.ParameterUDPPort.Value);
            Door.DoorWork[10] = portBytes[0];
            Door.DoorWork[11] = portBytes[1];
            #endregion

            Door.ConnType = 10;
            Door.EquptTime = (decimal)DateTime.Now.ToOADate();
            Door.ProductionDate = (decimal)DateTime.Parse(par.ParameterProductionDate).ToOADate();
        }

        private string FillString(string inStr, int outLen)
        {
            if (inStr.Length != outLen)
            {
                if (inStr.Length > outLen)
                {
                    return inStr.Substring(0, outLen);
                }
                else
                {
                    int iCount = outLen - inStr.Length;
                    return inStr + new string('F', iCount);
                }
            }
            return inStr;
        }

        private void InsertDoor(APIModel_WorkParameter par)
        {
            string SN = par.DeviceID;
            Equipment Door = new Equipment();
            #region 初始化字段，设置默认值
            Door.EquptID = 0;
            Door.EquptName = SN;
            Door.EquptType = FC8280EquptType;//eFC8280HTTP
            Door.LctnID = 1;
            Door.EquptSN = SN;
            Door.CardCount = 0;
            Door.SequenceCard = 0;
            Door.CardcountOnline = 0;
            Door.SequencecardOnline = 0;
            Door.TCPPar = new byte[139];
            Door.Deadline = 65535;
            Door.SystemPar = new byte[92];
            Door.LockType = 1;//1--不输出（默认）  COM & NC
            Door.DoorOpenType = 0;
            Door.LockDoorType = 0;
            Door.ReaderPar = new byte[280];
            Door.DoorWork = new byte[228];
            Door.LockOpenTime = new byte[225];
            Door.ReadErrCardAlarm = 0;
            Door.AlarmPassword = new byte[6];
            Door.CheckCardInOutState = 0;
            Door.ButtonPar = new byte[226];
            Door.MuchCardPar = new byte[2];
            Door.PortNum = 1;
            Door.EquptDesc = SN;
            Door.ConnType = 1;
            Door.COMPort = 1;
            Door.CommBaudrate = 19200;
            Door.NetPort = 8000;
            Door.EquptEnabled = 1;
            Door.ConnPassword = new byte[4];
            Door.EquptTest = 0;
            Door.EquptFirstCheckMode = new byte[2];
            Door.EquptMuchCardCheckMode = new byte[2];
            Door.RecordSaveMode = 0;
            Door.AlarmTime = 0;
            Door.ICCardPar = new byte[3];
            Door.CardDeadlineTipDay = 0;
            Door.MuchCardCheckEx = new byte[3];
            Door.AreaCheckInOut = 0;
            Door.AreaLockInteraction = 0;
            Door.BothWayCheckPar = 0;
            Door.SetupDateTime = (decimal)DateTime.Now.ToOADate();
            Door.DisassemblyAlarmPar = 0;
            Door.ReaderDisassemblyAlarmPar = 0;
            Door.ScreenShowName = 1;
            Door.ReaderByFaceDevice = 0;
            Door.DisplayBodyTmp = 1;
            Door.DriveSMS = string.Empty;
            Door.ReadErrCardAlarmTimes = 3;
            Door.IsConnectEncrypt = 0;
            Door.EncryptKey = string.Empty;
            #endregion
            WorkParameterToDoor(par, Door);

            DBClient.Insertable(Door).ExecuteCommandIdentityIntoEntity();

            DTOCacheDoor cacheDoor = new DTOCacheDoor();
            cacheDoor.EquptSN = SN;
            cacheDoor.EquptID = Door.EquptID;
            cacheDoor.LastKeepaliveTime = DateTime.Now;
            cacheDoor.UploadStatusTime = DateTime.Now;
            cacheDoor.UploadStatus = 1;

            var lctn = DBClient.Queryable<Location>().Where(l => l.LctnID == Door.LctnID).First();

            cacheDoor.WorkParameter = par;
            cacheDoor.EquptAddr = Door.EquptAddr;
            cacheDoor.EquptName = Door.EquptName;
            cacheDoor.LctnID = lctn.LctnID;
            cacheDoor.LctnName = lctn.LctnName;
            cacheDoor.OnlineTime = DateTime.Now;

            Cache.SetDoor(cacheDoor);
        }

        /// <summary>
        /// 设备拉取参数
        /// </summary>
        /// <param name="door"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task<GetWorkParameterResult> GetDoorWorkParameter(DTOCacheDoor cacheDoor)
        {
            Equipment Door = await DBClient.Queryable<Equipment>()
                .Where(it => it.EquptID == cacheDoor.EquptID).FirstAsync();
            if (Door == null) return null;
            if (cacheDoor.WorkParameter == null) return null;

            GetWorkParameterResult par = new GetWorkParameterResult();
            par.SetFaceDeviceDetail(cacheDoor.WorkParameter);

            par.DeviceName = Door.EquptName;
            if (Door.ScreenShowName.Value == 1)
                par.ParameterCompanyName = Door.EquptName;
            else
                par.ParameterCompanyName = string.Empty;


            #region 系统参数
            //语言选择 0，中文；1，英文；2，繁体
            par.ParameterLanguageChoose = Door.DriveLanguage.Value;
            //设备音量  0-10；0--关闭声音；10--最大声音
            par.ParameterVolume = Door.DriveVolume.Value;

            //语音模式 0,不播报；1，播放名字; 2,播放问候语;3,播放名字和问候语
            par.ParameterVoiceMode = Door.DoorWork[0];

            //陌生人语音 0，不播报;1,播报假体;2，播报陌生人；3，播报假体和陌生人
            par.ParameterStrangerVoice = Door.DoorWork[1];

            //问候语 0，请通行;1,欢迎光临;2，时间问候语
            par.ParameterGrettings = Door.DoorWork[2];

            //亮度设置 1-10
            par.ParameterBrightness = Door.DoorWork[3];

            //曝光设置 -3-3
            par.ParameterExposure = ((int)Door.DoorWork[4]) - 10;


            #region KeypadPar 菜单管理密码
            if (Door.KeypadPar[0] != 0xFF)
            {
                par.ParameterLoginPassword = ModTool.ByteToHex(Door.KeypadPar).Substring(0, 8).Replace("F", string.Empty);
            }
            else
            {
                par.ParameterLoginPassword = string.Empty;//表示没有密码
            }
            #endregion

            // 红外图像开关 0--关闭；1--开启
            par.ParameterIR = Door.DoorWork[5];
            #endregion

            #region 门禁参数
            //WG输出字节


            //parameterAccessType |出入类型 0,入门；1，出门
            par.ParameterAccessType = Door.EquptAddr;

            //parameterWgFormat  WG输出格式 26 / 34
            par.ParameterWgFormat = (Door.ReaderByte <= 3 ? 26 : 34);


            //parameterKeepOpenDoor --开门保持时间 1-65535（s）
            par.ParameterKeepOpenDoor = Door.OpenDoorTime;

            #region 识别间隔参数
            par.ParameterIntervalRecoSwitch = Door.ReaderInterval[1];
            par.ParameterRecgInterval = (int)ModTool.ByteToInt32(new byte[] {
                Door.SystemPar[17],
                Door.SystemPar[18] });
            #endregion

            //自由通行（免验证）0--禁止；1--启用
            #region ProhibitCheck 全卡开门参数
            par.ParameterLaissezSwitch = Door.ProhibitCheck[0];
            #endregion

            #endregion

            #region 报警参数

            //消防报警功能开关 0--禁用；1--启用, 禁用之后报警就不会触发
            par.ParameterFireAlarm = Door.FireAlarm.Value;


            //开门超时报警功能
            #region LongOpenAlarm 开门超时提示参数

            par.ParameterDoorLongOpenAlarmSwitch = Door.LongOpenAlarm[0];
            par.ParameterDoorSensorDelay = Door.LongOpenAlarm[2];
            #endregion


            //门磁报警功能
            #region DoorStateAlarm 门磁报警参数
            Door.DoorStateAlarm = new byte[225];
            par.ParameterDoorAlarmSwitch = Door.DoorStateAlarm[0];
            #endregion
            #endregion

            #region 人脸识别
            //人脸识别阈值 1-99
            par.ParameterFaceThreshold = Door.FaceRecognitionThreshold.Value;

            //识别距离
            par.ParameterDistance = Door.FaceCheckDist.Value;

            //活体检测
            par.ParameterPreview = Door.FaceCheckType.Value;

            //活体检测阈值 1-99
            par.ParameterFaceIRThreshold = Door.FaceBioassaySimilarity.Value;

            //补光灯模式  ；0--一直关 1--一直亮；2--检测到人员时开
            par.ParameterLightSwitch = Door.FaceLEDMode.Value;

            //口罩识别开关 0--禁止；1--启用
            par.ParameterMask = Door.FaceMouthmufflePar.Value;

            //口罩识别阈值： 1-99
            par.ParameterMaskThreshold = Door.DoorWork[6];

            #region  BodyTemperaturePar 体温检测开关及格式


            switch (Door.BodyTemperaturePar)
            {
                case 0:
                    par.ParameterTempSwitch = 0;
                    par.ParameterFahrenheitSwitch = 0;
                    par.ParameterTempThresholdMax = (float)37.5;
                    break;
                case 1:
                    par.ParameterTempSwitch = 1;
                    par.ParameterFahrenheitSwitch = 0;
                    par.ParameterTempThresholdMax = (((float)Door.BodyTemperatureAlarmPar.Value) / (float)10);
                    break;
                case 2:
                    par.ParameterTempSwitch = 1;
                    par.ParameterFahrenheitSwitch = 1;
                    par.ParameterTempThresholdMax = (((float)Door.BodyTemperatureAlarmPar.Value) / (float)10);
                    break;

                default:
                    break;
            }

            #endregion

            //打卡现场照片保存开关
            par.ParameterSavePicture = Door.SavePhoto.Value;
            #endregion


            #region 其他功能
            //是否存储陌生人记录，0:不存储，1:存储
            par.ParameterSaveExternalvisitors = Door.DoorWork[7];
            #endregion

            #region 网络参数

            //调试开关 0-关闭；1-打开
            par.ParameterEnableTelnet = Door.DoorWork[8];

            //web登陆开关 0-关闭；1-打开
            par.ParameterEnableWeb = Door.DoorWork[9];

            //UDP端口号 （UDP广播搜索发现用）
            par.ParameterUDPPort= (int)ModTool.ByteToInt32(new byte[] {
                Door.DoorWork[10],
                Door.DoorWork[11] });
            #endregion

            return par;
        }

        #region 开门时段
        /// <summary>
        /// 获取所有的开门时段
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task<List<APIModel_TimeGroupDetail>> GetTimeGroup()
        {
            var list = await DBClient.Queryable<TimePiece>().OrderBy(t => t.TimePieceIndex).ToListAsync();

            List<APIModel_TimeGroupDetail> result = new List<APIModel_TimeGroupDetail>(64);
            WeekTimeGroup timeGroup = new WeekTimeGroup();
            foreach (var dbTime in list)
            {
                APIModel_TimeGroupDetail detail = new APIModel_TimeGroupDetail()
                {
                    Num = dbTime.TimePieceIndex
                };
                timeGroup.SetBytes(dbTime.TimePieceBuf);
                detail.Week1 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Monday));
                detail.Week2 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Tuesday));
                detail.Week3 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Wednesday));
                detail.Week4 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Thursday));
                detail.Week5 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Friday));
                detail.Week6 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Saturday));
                detail.Week7 = DayTimegroupToString(timeGroup.get_Item(WeekTimeGroup.Sunday));
                result.Add(detail);
            }
            return result;
        }

        private string DayTimegroupToString(DayTimeGroup day)
        {
            //返回值格式 00:00--23:59/00:00--00:00/00:00--00:00/00:00--00:00/00:00--00:00/00:00--00:00/00:00--00:00/00:00--00:00
            List<string> sections = new List<string>(8);
            for (int i = 0; i < 8; i++)
            {
                var Segment = day.get_Item(i);
                sections.Add($"{Segment.BeginTime:HH:mm}--{Segment.EndTime:HH:mm}");
            }
            return string.Join('/', sections);

        }
        #endregion

        #endregion

        /// <summary>
        /// 更新门的上传状态
        /// </summary>
        /// <param name="oCacheDevice"></param>
        /// <exception cref="NotImplementedException"></exception>
        internal async Task UpdateDoorUploadStatus(DTOCacheDoor cacheDoor)
        {
            await DBClient.Updateable<Equipment>()
            .SetColumns(it => it.EquptTime == (decimal)cacheDoor.OnlineTime.ToOADate())//SetColumns是可以叠加的 写2个就2个字段赋值
            .SetColumns(it => it.EquptStatus == 1)
            .SetColumns(it => it.COMPort == 255)
            .SetColumns(it => it.DoorOpenType == (byte)cacheDoor.DoorStatus)
            .SetColumns(it => it.LockDoorType == (byte)cacheDoor.AlarmStatus)
            .Where(it => it.EquptID == cacheDoor.EquptID)
            .ExecuteCommandAsync();
        }
    }
}
